package com.geek.javase.ch17.work.tcpwork.tcp6;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/*
 *@Date 2025/11/4
 *@Author wangpeng
 *@Description
 *需求6：当服务器只是读取消息，客户端写出消息，此时一个服务器可以接收多个客户端（解决方案：线程池，优化需求5）
 */
public class TCPServer {
    // 存储所有客户端连接的线程安全列表，用于管理客户端连接
    private static CopyOnWriteArrayList<Socket> clients = new CopyOnWriteArrayList<>();
    // 最大客户端连接数限制常量
    private static final int MAX_CLIENTS = 5;
    public static void main(String[] args) {
        System.out.println("-------服务器--------");
        ServerSocket ss = null;
        // 创建线程池，用于处理客户端连接，避免为每个客户端创建新线程
        //ThreadPool threadPool = new ThreadPool(4,1);
        ThreadPool threadPool = new ThreadPool(2,1);
        try{
            // 创建服务器，绑定8899端口开始监听客户端连接
            ss = new ServerSocket(8899);
            // 无限循环，持续监听客户端连接请求
            while(true){
                //接收客户端
                //阻塞等待客户端连接请求，接收到连接后返回客户端Socket
                Socket s = ss.accept();
                System.out.println(s.getRemoteSocketAddress()+"已上线");
                //启动读线程
                // 使用线程池执行ReadThread任务，实现服务器只读取消息的功能
                threadPool.execute(new ReadThread(s));
                if(clients.size() == MAX_CLIENTS){
                    ss.close();
                    ss = null;
                    //等待，main主线程进入阻塞状态
                    // 使用LockSupport使主线程进入阻塞状态，等待唤醒
                    LockSupport.park();
                    //等待，线程归还到线程池
                    // 等待一段时间确保线程资源释放回线程池
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    // 重新创建服务器Socket继续接受新的客户端连接
                    ss = new ServerSocket(8899);
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            if(ss!= null){
                try {
                    ss.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
